/**
 ******************************************************************************
 * @file    locator.c
 * @brief   locator program body
 ******************************************************************************
 * @attention
 ******************************************************************************
 */
/* includes ------------------------------------------------------------------*/
#include "locator.h"
/* Private includes ----------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "rtc.h"
#include "delay.h"
#include "debug.h"
#include "cJSON.h"
#include "gps.h"
#include "lora.h"
#include "nb_iot.h"
#include "step.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/**
 * @brief 初始化定位器板上所有硬件外设
 * @param
 * @return
 */
void Locator_Init(void)
{
    /* GPS */
    GPS_Init();
    /* LoRa */
    LoRa_Init();
    /* NB-IoT */
    NB_IoT_Init();
    /* Step */
    Step_Init();
}

/**
 * @brief 定位器进入低功耗模式
 * @param
 * @return
 */
void Locator_EnterLowPowerMode(void)
{
    /* GPS */
    GPS_EnterLowPowerMode();
    /* NB-IoT */
    NB_IoT_EnterLowPowerMode();

    /* 主控芯片最后进入低功耗模式 ，设置实时时钟唤醒待机模式*/
    /* 设置实时时钟唤醒待机模式 */
    /* 查看当前rtc时间 */
    RTC_TimeTypeDef rtcTime = {0};
    HAL_RTC_GetTime(&hrtc, &rtcTime, RTC_FORMAT_BIN);
    /* 设置闹钟 */
    RTC_AlarmTypeDef rtcAlarm = {0};
    rtcAlarm.AlarmTime.Hours = rtcTime.Hours;
    rtcAlarm.AlarmTime.Minutes = rtcTime.Minutes;
    rtcAlarm.AlarmTime.Seconds = rtcTime.Seconds + 20;
    rtcAlarm.Alarm = RTC_ALARM_A;
    HAL_RTC_SetAlarm(&hrtc, &rtcAlarm, RTC_FORMAT_BIN);
    Delay_ms(100);

    /* 准备进入待机模式 */
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // 唤醒标志位
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); // 待机标志位
    HAL_PWR_EnterSTANDBYMode();
}

/**
 * @brief 定位器退出低功耗模式
 * @param
 * @return
 */
void Locator_ExitLowPowerMode(void)
{
    /* GPS */
    GPS_ExitLowPowerMode();
    /* NB-IoT */
    NB_IoT_ExitLowPowerMode();
}

/**
 * @brief 获取GPS、步数
 * @param
 * @return
 */
void Locator_GetSensorData(locator_t *locator)
{
    char UTCTime[7] = {0};
    char status;        /* 位置有效标志。V=接收机警告，数据无效，A=数据有效 */
    double lat;         /* 纬度，前 2 字符表示度，后面的字符表示分 */
    char uLat;          /* 纬度方向：N-北，S-南 */
    double lon;         /* 经度，前 3 字符表示度，后面的字符表示分 */
    char uLon;          /* 经度方向：E-东，W-西 */
    char date[7] = {0}; /* 日期（dd 为日，mm 为月，yy 为年） */

    /* 获取GPS数据 */
    // char location[512] = "$GNRMC,013050.000,A,3106.67898,N,12113.52954,E,5.19,77.74,160125,,,A,V*31";
    char location[2048] = {0};
    // char location[1024] = "$GNRMC,003703.007,A,3114.89203,N,12045.26865,E,0.71,0.00,240825,,,A,V*0F";
    /* "$GNRMC,013050.000,A,3106.67898,N , 12113.52954,E ,5.19,77.74,160125,,,A,V*31" */
    // GPS_GetLocation((uint8_t*)&location);
    /* $--RMC,UTCTime,status,lat,uLat,lon,uLon,spd,cog,date,mv,mvE,mode*CS<CR><LF> */
    /* 确保GPS数据是有效数据 */
    char *GNRMC;
    while (1)
    {
        GPS_GetLocation((uint8_t*)&location);
        GNRMC = strstr(location, "$GNRMC");
        sscanf(GNRMC, "%*[^AV]%c", &status);
        if (status == 'A')
        {
            LOG_DEBUG("GPS数据有效");
            break;
        }
        else
        {
            LOG_DEBUG("GPS数据无效");
            Delay_ms(1000);
        }
    }

    /* 使用sscanf解析GNRMC字符串 */
    sscanf(GNRMC, "$GNRMC,%6c.%*[^,],%c,%lf,%c,%lf,%c,%*f,%*f,%6c",
           UTCTime,
           &status,
           &lat,
           &uLat,
           &lon,
           &uLon,
           date);

    LOG_DEBUG("时间:%s,位置有效标志:%c,纬度:%lf,纬度方向:%c,经度:%lf,经度方向:%c,日期:%s",
              UTCTime,
              status,
              lat,
              uLat,
              lon,
              uLon,
              date);
    /* 串口打印如下 */
    //	[locator.c:117]时间:013050,位置有效标志:A,纬度:3106.678980,纬度方向:N,经度:12113.529540,
    //	经度方向:E,日期:160125

    /* 处理字符串，获得最终的时间(2025-08-21 12:38:25) */
    sprintf((char *)locator->UTCTime, "20%c%c-%c%c-%c%c %c%c:%c%c:%c%c",
            date[4],
            date[5],
            date[2],
            date[3],
            date[0],
            date[1],
            UTCTime[0],
            UTCTime[1],
            UTCTime[2],
            UTCTime[3],
            UTCTime[4],
            UTCTime[5]);

    /* 将0时区的时间转到北京时区，北京时区比0时区多8小时 */
    Locator_ConvertUTCToBeijingTime(locator->UTCTime, locator->BeijingTime);

    LOG_DEBUG("BeijingTime: %s", locator->BeijingTime);
    /* 串口打印如下 */
    //	[locator.c:162]UTCTime: 2025-01-60 01:30:50

    /* 计算最终的经纬度 */
    locator->latitude = (int)(lat / 100) + (lat - 100 * (int)(lat / 100)) / 60;
    locator->latitudeDirection[0] = uLat;
    locator->longitude = (int)(lon / 100) + (lon - 100 * (int)(lon / 100)) / 60;
    locator->longitudeDirection[0] = uLon;
    // LOG_DEBUG("latitude: %f", locator->latitude);
    // LOG_DEBUG("longitude: %f", locator->longitude);

    /* 获取步数 */
    locator->stepCount = Step_GetCount();
    LOG_DEBUG("step: %d", locator->stepCount);
}

/**
 * @brief 拼接要上传的jSON数据，将数据转换成json格式字符串
 * @param
 * @return
 */
void Locator_ConvertDataToJSON(locator_t *locator)
{
    /* 添加单片机ID号 */
    sprintf((char *)locator->mcuID, "%08X%08X%08X", (unsigned int)HAL_GetUIDw2(), (unsigned int)HAL_GetUIDw1(), (unsigned int)HAL_GetUIDw0());

    /* 将定位器结构体换为jSON格式 */
    /* 创建json结构体对象 */
    cJSON *json = cJSON_CreateObject();

    /* 添加结构体到json对象中 */
    cJSON_AddStringToObject(json, "ID", (char *)locator->mcuID);
    cJSON_AddNumberToObject(json, "lat", locator->latitude);
    cJSON_AddStringToObject(json, "uLat", (char *)locator->latitudeDirection);
    cJSON_AddNumberToObject(json, "lon", locator->longitude);
    cJSON_AddStringToObject(json, "uLon", (char *)locator->longitudeDirection);
    cJSON_AddStringToObject(json, "BeijingTime", (char *)locator->BeijingTime);
    cJSON_AddNumberToObject(json, "step", locator->stepCount);

    /* 将json对象转化为json字符串 */
    char *jsonStr = cJSON_PrintUnformatted(json);
    //	LOG_DEBUG("jsonStr:%s", jsonStr);
    memset((char *)locator->uploadData, 0, strlen((char *)locator->uploadData));
    memcpy((char *)locator->uploadData, jsonStr, strlen(jsonStr));
    LOG_DEBUG("Upload:%s", (char*)locator->uploadData);
    /* 串口打印如下 */
    //	[locator.c:207]Upload:{"ID":"6703324056667849066EFF55","lat":31.0667898,"uLat":"N","lon":121.1352954,"uLon":"E","UTCTime":"2025-01-16 01:30:50","step":36}

    /* 释放堆内存 */
    cJSON_Delete(json);

    /* 清除常量池里的字符串 */
    cJSON_free(jsonStr);
}

/**
 * @brief 将要上传的JSON字符串发送到服务器
 * @param
 * @return
 */
uint8_t Locator_SendDataToServer(locator_t *locator)
{
    /* 优先通过NB_IoT发送数据 */
    uint8_t isDataSent = 0XFF;
    isDataSent = NB_IoT_SendData(locator->uploadData);
    LOG_DEBUG("isDataSent:%d", (int)isDataSent);
    /* 判断NB_IoT是否成功发送数据 */
    if (!isDataSent)
    {
        LOG_DEBUG("NB_IoT send data successfully");
    }
    else
    {
        LOG_DEBUG("NB_IoT fail to send data, LoRa start");
        isDataSent = LoRa_SendData(locator->uploadData);
        if (!isDataSent)
        {
            LOG_DEBUG("LoRa send data successfully");
        }
        else
        {
            LOG_DEBUG("LoRa fail to send data");
            return 1;
        }
    }

    return 0;
}

/**
 * @brief 将0时区的时间转到北京时区，北京时区比0时区多8小时
 *
 */
void Locator_ConvertUTCToBeijingTime(uint8_t *UTCTime, uint8_t *BeijingTime)
{
    struct tm utc;
    uint32_t year, month, day, hour, minute, second;    

    sscanf((char *)UTCTime, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);

    utc.tm_year = year - 1900;
    utc.tm_mon = month - 1;
    utc.tm_mday = day;
    utc.tm_hour = hour;
    utc.tm_min = minute;
    utc.tm_sec = second;

    /* 计算UTC的时间戳 */
    time_t UTCTimestamp = mktime(&utc);

    /* 计算北京的时间戳 */
    time_t BeijingTimestamp = UTCTimestamp + 8 * 3600;

    /* 将时间戳转换成tm结构体 */
    struct tm *Beijing = localtime(&BeijingTimestamp);

    sprintf((char *)BeijingTime, "%d-%d-%d %d:%d:%d", Beijing->tm_year + 1900, Beijing->tm_mon + 1, Beijing->tm_mday, Beijing->tm_hour, Beijing->tm_min, Beijing->tm_sec);
}
